{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2-dimensional representation\n",
    "\n",
    "Ensembles of neurons represent information.\n",
    "In Nengo, we represent that information with\n",
    "real-valued vectors -- lists of numbers.\n",
    "In this example, we will represent a two-dimensional vector\n",
    "with a single ensemble of leaky integrate-and-fire neurons."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Create the network\n",
    "\n",
    "Our model consists of a single ensemble,\n",
    "which we will call `Neurons`.\n",
    "It will represent a two-dimensional signal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "import nengo\n",
    "\n",
    "model = nengo.Network(label='2D Representation')\n",
    "with model:\n",
    "    # Our ensemble consists of 100 leaky integrate-and-fire neurons,\n",
    "    # and represents a 2-dimensional signal\n",
    "    neurons = nengo.Ensemble(100, dimensions=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Provide input to the model\n",
    "\n",
    "The signal that an ensemble represents varies over time.\n",
    "We will use a simple sine and cosine wave\n",
    "as examples of continuously changing signals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with model:\n",
    "    # Create input nodes representing the sine and cosine\n",
    "    sin = nengo.Node(output=np.sin)\n",
    "    cos = nengo.Node(output=np.cos)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Connect the input to the ensemble"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with model:\n",
    "    # The indices in neurons define which dimension the input will project to\n",
    "    nengo.Connection(sin, neurons[0])\n",
    "    nengo.Connection(cos, neurons[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Probe outputs\n",
    "\n",
    "Anything that is probed will collect the data it produces over time,\n",
    "allowing us to analyze and visualize it later.\n",
    "Let's collect all the data produced."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with model:\n",
    "    sin_probe = nengo.Probe(sin, 'output')\n",
    "    cos_probe = nengo.Probe(cos, 'output')\n",
    "    neurons_probe = nengo.Probe(neurons, 'decoded_output', synapse=0.01)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Run the model\n",
    "\n",
    "In order to run the model, we have to create a simulator.\n",
    "Then, we can run that simulator over and over again\n",
    "without affecting the original model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:\n",
    "    sim.run(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot the decoded output of the ensemble\n",
    "plt.figure()\n",
    "plt.plot(sim.trange(), sim.data[neurons_probe], label=\"Decoded output\")\n",
    "plt.plot(sim.trange(), sim.data[sin_probe], 'r', label=\"Sine\")\n",
    "plt.plot(sim.trange(), sim.data[cos_probe], 'k', label=\"Cosine\")\n",
    "plt.legend()\n",
    "plt.xlabel('time [s]');"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
